.TH NETTRACE 8 "20 JULY 2022" Linux "User Manuals"
.SH NAME
.PP
nettrace \- Linux系统下的网络报文跟踪、网络问题诊断工具
.SH SYNOPSIS
.PP
\fB\fCnettrace\fR [选项]
.SH DESCRIPTION
.PP
\fB\fCnettrace\fR是基于eBPF的集网络报文跟踪（故障定位）、网络故障诊断、网络异常监控于一体的网
络工具集，旨在能够提供一种更加高效、易用的方法来解决复杂场景下的网络问题。
.SH OPTIONS
.TP
\fB\fC\-s,\-\-saddr\fR \fIsource_address\fP
根据IP源地址来进行报文筛选
.TP
\fB\fC\-d,\-\-daddr\fR \fIdest_address\fP
根据IP目的地址来进行报文筛选
.TP
\fB\fC\-\-addr\fR \fIaddress\fP
根据IP源地址或者目的地址来进行报文筛选
.TP
\fB\fC\-S,\-\-sport\fR \fIsource_port\fP
根据UDP/TCP源端口进行报文筛选
.TP
\fB\fC\-D,\-\-dport\fR \fIdest_port\fP
根据UDP/TCP目的端口进行报文筛选
.TP
\fB\fC\-\-port\fR \fIport\fP
根据UDP/TCP源端口或者目的端口进行报文筛选
.TP
\fB\fC\-p,\-\-proto\fR \fIprotocol\fP
根据报文的协议（三层或者四层）进行过滤，如\fI\-p udp\fP
.TP
\fB\fC\-\-netns\fR \fInetns_inode\fP
根据网络命名空间进行过滤。
.IP
该参数后面跟的是网络命名空间的inode，可以通过
\fB\fCls \-l /proc/<pid>/ns/net\fR
来查看对应进程的网络命名空间的inode号
.TP
\fB\fC\-\-netns\-current\fR
仅显示当前网络命名空间的报文，等价于\fB\fC\-\-netns <当前网络命名空间的inode>\fR
.TP
\fB\fC\-\-pid\fR \fIpid\fP
根据进程号进行过滤
.TP
\fB\fC\-t,\-\-trace\fR \fItraces\fP
要启用（跟踪）的内核函数、tracepoint。
.IP
这里将这些被跟踪的对象（内核函数、tracepoint等）简称为跟踪器，
所有的跟踪器以树状图的方式被组织了起来，使用命令：
\fInettrace \-t ?\fP
可以查看所有的跟踪器。
.IP
默认情况下，大部分的跟踪器会被启用，一些设备相关的跟踪器（如ipvlan、bridge等）默认
不启用。使用参数\fI\-t all\fP可启用所有的跟踪器。
.IP
可以同时指定多个跟踪器，以\fI,\fP分隔，比如\fInettrace \-t ip,link,kfree_skb\fP。
可以指定跟踪器的目录，也可以直接指定跟踪器。
.TP
\fB\fC\-\-ret\fR
显示被跟踪的内核函数的返回值
.TP
\fB\fC\-\-detail\fR
显示跟踪详细信息，包括当前的进程、网口和CPU等信息
.TP
\fB\fC\-\-date\fR
以时间格式打印（以2022\-10\-24 xx:xx:xx.xxxxxx格式打印），而不是时间戳
.TP
\fB\fC\-\-basic\fR
启用\fB\fCbasic\fR跟踪模式。默认情况下，启用的是生命周期跟踪模式。启用该模式后，会直接打印
出报文所经过的内核函数/tracepoint
.TP
\fB\fC\-\-diag\fR
启用诊断模式
.TP
\fB\fC\-\-diag\-quiet\fR
只显示出现存在问题的报文，不显示正常的报文
.TP
\fB\fC\-\-diag\-keep\fR
持续跟踪。\fB\fCdiag\fR模式下，默认在跟踪到异常报文后会停止跟踪，使用该参数后，会持续跟踪下去。
.TP
\fB\fC\-\-sock\fR
启用套接口模式。这个模式下，不会再跟踪报文，而会跟踪套接口。
.TP
\fB\fC\-\-hooks\fR
打印netfilter上的钩子函数
.TP
\fB\fC\-\-drop\fR
进行系统丢包监控，取代原先的\fB\fCdroptrace\fR
.TP
\fB\fC\-\-drop\-stack\fR
打印kfree_skb内核函数的调用堆栈
.TP
\fB\fC\-\-min\-latency\fR
根据报文的寿命进行过滤，仅打印处理时长超过该值的报文，单位为ms。该参数仅在默认和\fB\fCdiag\fR模式下可用。
.TP
\fB\fC\-v\fR
显示程序启动的日志信息
.TP
\fB\fC\-\-debug\fR
显示调试信息
.SH EXAMPLES
.SS 生命周期跟踪
.TP
跟踪源地址为\fB\fC192.168.1.8\fR的ping报文：
\fInettrace \-p icmp \-s 192.168.1.8\fP
.TP
跟踪源地址为\fB\fC192.168.1.8\fR的ping报文在IP协议层和ICMP协议层的路径：
\fInettrace \-p icmp \-s 192.168.1.8 \-t ip,icmp\fP
.TP
显示详细信息：
\fInettrace \-p icmp \-s 192.168.1.8 \-\-detail\fP
.SS 诊断模式
.PP
使用方式与上面的一致，加个\fB\fCdiag\fR参数即可使用诊断模式。上文的生命周期模式对于使用者的
要求比较高，需要了解内核协议栈各个函数的用法、返回值的意义等，易用性较差。诊断模式是在
生命周期模式的基础上，提供了更加丰富的信息，使得没有网络开发经验的人也可进行复杂
网络问题的定位和分析。
.PP
比于普通模式，诊断模式提供了更多的可供参考的信息，包括当前报文经过了iptables的哪些表和
哪些链、报文发生了NAT、报文被克隆了等。诊断模式设置了三种提示级别：
.RS
.IP \(bu 2
\fB\fCINFO\fR：正常的信息提示
.IP \(bu 2
\fB\fCWARN\fR：警告信息，该报文可能存在一定的问题，需要关注
.IP \(bu 2
\fB\fCERROR\fR：异常信息，报文发生了问题（比如被丢弃）。
.RE
.PP
如果当前报文存在\fB\fCERROR\fR，那么工具会给出一定的诊断修复建议，并终止当前诊断操作。通过添
加\fB\fCdiag\-keep\fR可以在发生\fB\fCERROR\fR事件时不退出，继续进行跟踪分析。下面是发生异常时的日志：
.PP
.RS
.nf
\&./nettrace \-p icmp \-\-diag \-\-saddr 192.168.122.8
begin trace...
***************** ffff889fb3c64f00 ***************
[4049.295546] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295566] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[4049.295578] [nft_do_chain        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *iptables table:nat, chain:PREROUT* *packet is accepted*
[4049.295594] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *bridge in chain: PRE_ROUTING*
[4049.295612] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295624] [ip_rcv              ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295629] [ip_rcv_core         ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295640] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: PRE_ROUTING*
[4049.295644] [ip_rcv_finish       ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295655] [ip_route_input_slow ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295664] [fib_validate_source ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295683] [ip_forward          ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0
[4049.295687] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *ipv4 in chain: FORWARD* *packet is dropped by netfilter (NF_DROP)*
[4049.295695] [nft_do_chain        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *iptables table:filter, chain:FORWARD* *packet is dropped by iptables/iptables\-nft*
[4049.295711] [kfree_skb           ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 0 *packet is dropped by kernel*
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- ANALYSIS RESULT \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
[1] ERROR happens in nf_hook_slow(netfilter):
        packet is dropped by netfilter (NF_DROP)
    fix advice:
        check your netfilter rule

[2] ERROR happens in nft_do_chain(netfilter):
        packet is dropped by iptables/iptables\-nft
    fix advice:
        check your iptables rule

[3] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        nf_hook_slow+0x96
    drop reason:
        NETFILTER_DROP

analysis finished!

end trace...
.fi
.RE
.PP
从这里的日志可以看出，在报文经过iptables的filter表的forward链的时候，发生了丢包。在
诊断结果里，会列出所有的异常事件，一个报文跟踪可能会命中多条诊断结果。这里的诊断建议是让
用户检查iptables中的规则是否存在问题。
.PP
其中，\fB\fCkfree_skb\fR这个跟踪点是对\fB\fCdrop reason\fR内核特性（详见droptrace中的介绍）做了
适配的，可以理解为将droptrace的功能集成到了这里的诊断结果中，这里可以看出其给出的丢包
原因是\fB\fCNETFILTER_DROP\fR。因此，可以通过一下命令来监控内核中所有的丢包事件以及丢包原因：
.PP
\fInettrace \-t kfree_skb \-\-diag \-\-diag\-keep\fP
.SS 丢包监控
.PP
使用命令\fB\fCnettrace \-\-drop\fR可以对系统中的丢包事件进行监控，对于支持内核特性
\fB\fCskb drop reason\fR的内核，这里还会打印出丢包原因。可以通过查看
\fB\fC/tracing/events/skb/kfree_skb/format\fR来判断当前系统是否支持该特性。
.PP
该模式下使用的效果与原先的\fB\fCdroptrace\fR完全相同，如下所示：
.PP
.RS
.nf
nettrace \-\-drop
begin trace...
[142.097193] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AR, reason: NOT_SPECIFIED, tcp_v4_rcv+0x81
[142.331798] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:A, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83
[142.331857] TCP: 162.241.189.135:57022 \-> 172.27.0.6:22 seq:299038593, ack:3843597961, flags:AP, reason: NOT_SPECIFIED, tcp_v4_do_rcv+0x83
[146.136576] TCP: 127.0.0.1:43582 \-> 127.0.0.1:9999 seq:3819454691, ack:0, flags:S, reason: NO_SOCKET, tcp_v4_rcv+0x81
[146.220414] TCP: 169.254.0.138:8186 \-> 172.27.0.6:40634 seq:8486084, ack:2608831141, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126
[146.533728] TCP: 127.0.0.1:36338 \-> 127.0.0.1:56100 seq:1110580666, ack:1951926207, flags:A, reason: TCP_INVALID_SEQUENCE, tcp_validate_incoming+0x126
[147.255946] TCP: 20.44.10.122:443 \-> 192.168.255.10:42878 seq:2950381253, ack:211751623, flags:A, reason: NOT_SPECIFIED, tcp_rcv_state_process+0xe9
.fi
.RE
.PP
同样可以使用\fB\fCman dropreason\fR命令来查看对应的丢包原因的详细解释。对于不支持
\fB\fCskb drop reason\fR特性的内核，该模式下将不会打印丢包原因字段，效果如下所示：
.PP
.RS
.nf
nettrace \-\-drop
begin trace...
[2016.965295] TCP: 162.241.189.135:45432 \-> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:AR, tcp_v4_rcv+0x50
[2017.201315] TCP: 162.241.189.135:45432 \-> 172.27.0.6:22 seq:133152310, ack:2529234288, flags:A, tcp_v4_do_rcv+0x70
[2019.041344] TCP: 176.58.124.134:37441 \-> 172.27.0.6:443 seq:1160140493, ack:0, flags:S, tcp_v4_rcv+0x50
[2021.867340] TCP: 127.0.0.1:34936 \-> 127.0.0.1:9999 seq:1309795878, ack:0, flags:S, tcp_v4_rcv+0x50
[2024.997146] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AR, tcp_v4_rcv+0x50
[2025.235953] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:A, tcp_v4_do_rcv+0x70
[2025.235967] TCP: 162.241.189.135:46756 \-> 172.27.0.6:22 seq:1304582308, ack:1354418612, flags:AP, tcp_v4_do_rcv+0x70
.fi
.RE
.SS netfilter支持
.PP
网络防火墙是网络故障、网络不同发生的重灾区，因此\fB\fCnetfilter\fR工具对\fB\fCnetfilter\fR提供了
完美适配，包括老版本的\fB\fCiptables\-legacy\fR和新版本的\fB\fCiptables\-nft\fR。诊断模式下，
\fB\fCnettrace\fR能够跟踪报文所经过的\fB\fCiptables\fR表和\fB\fCiptables\fR链，并在发生由于iptables
导致的丢包时给出一定的提示，上面的示例充分展现出了这部分。出了对iptables的支持，
\fB\fCnettrace\fR对整个netfilter大模块也提供了支持，能够显示在经过每个HOOK点时对应的协议族
和链的名称。除此之外，为了应对一些注册到netfilter中的第三方内核模块导致的丢包问题，
\fB\fCnettrace\fR还可以通过添加参数\fB\fChooks\fR来打印出当前\fB\fCHOOK\fR上所有的的钩子函数，从而深入
分析问题：
.PP
.RS
.nf
\&./nettrace \-p icmp \-\-diag \-\-saddr 192.168.122.8 \-\-hooks
begin trace...
***************** ffff889faa054500 ***************
[5810.702473] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702491] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: PRE_ROUTING*
[5810.702504] [nft_do_chain        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *iptables table:nat, chain:PREROUT* *packet is accepted*
[5810.702519] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *bridge in chain: PRE_ROUTING*
[5810.702527] [__netif_receive_skb_core] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702535] [ip_rcv              ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702540] [ip_rcv_core         ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702546] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: PRE_ROUTING*
[5810.702551] [ip_rcv_finish       ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702556] [ip_route_input_slow ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702565] [fib_validate_source ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702579] [ip_forward          ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943
[5810.702583] [nf_hook_slow        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *ipv4 in chain: FORWARD* *packet is dropped by netfilter (NF_DROP)*
[5810.702586] [nft_do_chain        ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *iptables table:filter, chain:FORWARD* *packet is dropped by iptables/iptables\-nft*
[5810.702599] [kfree_skb           ] ICMP: 192.168.122.8 \-> 10.123.119.98 ping request, seq: 943 *packet is dropped by kernel*
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- ANALYSIS RESULT \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
[1] ERROR happens in nf_hook_slow(netfilter):
        packet is dropped by netfilter (NF_DROP)

    following hook functions are blamed:
        nft_do_chain_ipv4

    fix advice:
        check your netfilter rule

[2] ERROR happens in nft_do_chain(netfilter):
        packet is dropped by iptables/iptables\-nft
    fix advice:
        check your iptables rule

[3] ERROR happens in kfree_skb(life):
        packet is dropped by kernel
    location:
        nf_hook_slow+0x96
    drop reason:
        NETFILTER_DROP

analysis finished!

end trace...
.fi
.RE
.PP
可以看出，上面\fB\fCfollowing hook functions are blamed\fR中列出了导致当前\fB\fCnetfilter\fR
丢包的所有的钩子函数，这里只有\fB\fCiptables\fR一个钩子函数。
.SS sock跟踪
.PP
套接口跟踪在原理上与skb的basic模式很类似，只不过跟踪对象从skb换成了sock。常规的过滤参数，如ip、端口等，在该模式下都可以直接使用，基本用法如下所示：
.PP
.RS
.nf
sudo ./nettrace \-p tcp \-\-port 9999 \-\-sock
begin trace...
[2157947.050509] [inet_listen         ] TCP: 0.0.0.0:9999 \-> 0.0.0.0:0 info:(0 0)
[2157958.364842] [__tcp_transmit_skb  ] TCP: 127.0.0.1:36562 \-> 127.0.0.1:9999 info:(1 0)
[2157958.364875] [tcp_rcv_state_process] TCP: 0.0.0.0:9999 \-> 0.0.0.0:0 info:(0 0)
[2157958.364890] [tcp_rcv_state_process] TCP: 127.0.0.1:36562 \-> 127.0.0.1:9999 info:(1 0) timer:(retrans, 1.000s)
[2157958.364896] [tcp_ack             ] TCP: 127.0.0.1:36562 \-> 127.0.0.1:9999 info:(1 0) timer:(retrans, 1.000s)
[2157958.364906] [__tcp_transmit_skb  ] TCP: 127.0.0.1:36562 \-> 127.0.0.1:9999 info:(0 0)
[2157958.364917] [tcp_rcv_state_process] TCP: 127.0.0.1:9999 \-> 127.0.0.1:36562 info:(0 0)
[2157958.364921] [tcp_ack             ] TCP: 127.0.0.1:9999 \-> 127.0.0.1:36562 info:(0 0)
[2157959.365240] [tcp_write_timer_handler] TCP: 127.0.0.1:36562 \-> 127.0.0.1:9999 info:(0 0)
.fi
.RE
.PP
其中，\fB\fCinfo\fR里显示的内容分别是：报文在外数量、报文重传数量。\fB\fCtimer\fR显示的为当前套接口上的定时器和超时时间。目前，信息还在不断完善中。
.SH REQUIREMENTS
.PP
内核需要支持\fB\fCCONFIG_BPF\fR, \fB\fCCONFIG_KPROBE\fR, \fB\fCCONFIG_DEBUG_INFO_BTF\fR(可选)功能
.SH OS
.PP
Linux
.SH AUTHOR
.PP
Menglong Dong
.SH SEE ALSO
.PP
.BR nettrace-legacy (8), 
.BR dropreason (8)
